// main.go
package main

import (
	"context"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"net/http/httputil"
	"net/url"

	"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	"go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"

	_ "dyp.com/dyp/first-web/docs" // 必须导入生成的 docs 包,这个目录是通过“swag init -g main.go”命令生成的 （# -g 指定主文件路径）
	"github.com/gin-gonic/gin"
	"github.com/hashicorp/consul/api"
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
)

func SelectRandomInstance(services []*api.ServiceEntry) *api.ServiceEntry {
	return services[rand.Intn(len(services))]
}

func NewConsulClient(consulAddr string) (*api.Client, error) {
	config := api.DefaultConfig()
	config.Address = consulAddr // 如 "127.0.0.1:8500"
	return api.NewClient(config)
}

func DiscoverService(consulClient *api.Client, serviceName string) (string, error) {
	// 获取健康的服务实例列表
	services, _, err := consulClient.Health().Service(serviceName, "", true, nil)
	if err != nil {
		return "", fmt.Errorf("查询服务失败: %v", err)
	}

	if len(services) == 0 {
		return "", fmt.Errorf("服务 %s 无可用实例", serviceName)
	}

	// 负载均衡（随机选择实例）
	instance := SelectRandomInstance(services)
	address := instance.Service.Address
	if address == "" {
		address = instance.Node.Address // 如果服务未指定地址，使用节点地址
	}
	return fmt.Sprintf("http://%s:%d", address, instance.Service.Port), nil
}

func registerService() {
	config := api.DefaultConfig()
	config.Address = "10.120.137.235:8500" // Consul 地址
	client, err := api.NewClient(config)
	if err != nil {
		log.Fatal("Consul 连接失败:", err)
	}

	// 服务注册信息
	registration := &api.AgentServiceRegistration{
		ID:      "gin-service-1",  // 服务唯一ID
		Name:    "gin-service",    // 服务名称
		Port:    8080,             // Gin 服务端口
		Address: "10.120.137.235", // Gin 服务IP
		Check: &api.AgentServiceCheck{
			HTTP:     "http://10.120.137.235:8080/health", // 健康检查端点
			Interval: "10s",                               // 检查间隔
			Timeout:  "5s",                                // 超时时间
		},
	}

	// 执行注册
	err = client.Agent().ServiceRegister(registration)
	if err != nil {
		log.Fatal("注册服务失败:", err)
	}
	log.Println("服务注册成功")
}
func initTracer() *trace.TracerProvider {
	// 1. 配置 OTLP/HTTP 导出器（指向 Jaeger 的 OTLP 端口）
	exporter, err := otlptracehttp.New(context.Background(),
		otlptracehttp.WithEndpoint("10.120.137.235:4318"), // OTLP HTTP 端口
		otlptracehttp.WithInsecure(),                      // 非 TLS（生产环境应启用）
	)
	if err != nil {
		log.Fatalf("OTLP 导出器创建失败: %v", err)
	}

	// 2. 配置资源（标识服务）
	res, err := resource.New(context.Background(),
		resource.WithAttributes(
			semconv.ServiceNameKey.String("gin-service"),
		),
	)
	if err != nil {
		log.Fatalf("资源创建失败: %v", err)
	}

	// 3. 创建 Tracer Provider
	tp := trace.NewTracerProvider(
		trace.WithBatcher(exporter),
		trace.WithResource(res),
	)
	otel.SetTracerProvider(tp)

	// 设置传播器以支持W3C Trace Context
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
		propagation.TraceContext{},
		propagation.Baggage{},
	))

	return tp
}

// @title           Gin Swagger API
// @version         1.0
// @description     This is a sample Gin server with Swagger.
// @host            localhost:8080
// @BasePath        /
func main() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	tp := initTracer()
	defer tp.Shutdown(context.Background())

	r := gin.Default()

	// 1.自动追踪 HTTP 请求
	r.Use(otelgin.Middleware("gin-service"))

	// 2. JWT 认证中间件
	r.Use(func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token != "valid-token" {
			// c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
			log.Println("Unauthorized")
		} else {
			log.Println("Authorized")
		}
	})

	// 路由转发（类似 Spring Cloud Gateway 的 Route）
	r.GET("/poxy", ProxyHandler)

	// 添加 health 路由
	r.GET("/health", func(c *gin.Context) {
		// 添加实际健康检查逻辑（如数据库连接测试）
		c.JSON(200, gin.H{"status": "healthy"})
	})

	// 添加 Swagger 路由 http://localhost:8080/swagger/index.html
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	// 定义 API 路由组
	v1 := r.Group("/api/v1")
	{
		v1.GET("/hello", HelloHandler)
		v1.POST("/user", CreateUserHandler)
	}

	// 注册服务到Consul
	registerService()

	r.Run(":8080")
}

// ProxyHandler  转发示例接口
// @Summary      返回欢迎信息
// @Description  返回一个简单的欢迎字符串
// @Accept       json
// @Produce      json
// @Success      200  {string}  string  "Hello, World!"
// @Router       /poxy [get]
func ProxyHandler(c *gin.Context) {
	target, _ := url.Parse("http://10.120.137.235:8080/api/v1/hello")
	proxy := httputil.NewSingleHostReverseProxy(target)
	proxy.ServeHTTP(c.Writer, c.Request)
}

// HelloHandler 示例接口
// @Summary      返回欢迎信息
// @Description  返回一个简单的欢迎字符串
// @Tags         example
// @Accept       json
// @Produce      json
// @Success      200  {string}  string  "Hello, World!"
// @Router       /api/v1/hello [get]
func HelloHandler(c *gin.Context) {
	log.Println("HelloHandler")

	// 动态调用
	// 初始化 Consul 客户端
	consulClient, err := NewConsulClient("10.120.137.235:8500")
	if err != nil {
		panic(err)
	}
	// 1. 从 Consul 获取 user-service 地址
	targetURL, err := DiscoverService(consulClient, "gin-service")

	// 1. 从 Gin 上下文中获取 Span 上下文
	ctx := c.Request.Context()

	// 2. 手动创建业务 Span
	_, dbSpan := otel.Tracer("gin-service").Start(ctx, "save-to-database")
	defer dbSpan.End()
	// 3. 在业务 Span 中添加自定义标签
	dbSpan.SetAttributes(attribute.String("user_id", "12345"))
	// 4. 在业务 Span 中添加自定义事件
	dbSpan.AddEvent("User data saved successfully")

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	log.Print("target:" + targetURL)
	c.String(200, "Hello, World!")
}

// CreateUserHandler 创建用户
// @Summary      创建用户
// @Description  输入用户名并创建用户
// @Tags         user
// @Accept       json
// @Produce      json
// @Param        user  body  UserRequest  true  "用户信息"
// @Success      200  {object}  UserResponse
// @Failure      400  {object}  ErrorResponse
// @Router       /api/v1/user [post]
func CreateUserHandler(c *gin.Context) {
	log.Println("CreateUserHandler")
	// 实现代码...
	user := UserResponse{ID: 1, Name: "Alice"}
	c.JSON(http.StatusOK, user) // 通过 gin.Context 返回 JSON

}

// 定义请求/响应模型（需在 Swagger 中展示的模型）
type UserRequest struct {
	Name string `json:"name" example:"Alice"` // 示例值
}

type UserResponse struct {
	ID   uint   `json:"id" example:"1"`
	Name string `json:"name" example:"Alice"`
}

type ErrorResponse struct {
	Message string `json:"message" example:"Bad Request"`
}
